package io.plus.client;

import drds.common.Clock;
import io.plus.interactive.AsynchronousSocketChannelContext;
import io.plus.utils.thread.lock_capable_task.DefaultThreadFactory;
import io.plus.utils.thread.lock_capable_task.LockCapableRunnableThreadPoolExecutor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.LinkedBlockingQueue;

@Slf4j
@Data
public class ReConnectConfiguration {
    LinkedBlockingQueue<AsynchronousSocketChannelContext> queue = new LinkedBlockingQueue<>();
    /**
     * 用来重连的线程池
     */
    private volatile LockCapableRunnableThreadPoolExecutor threadPoolExecutor = null;
    /**
     * 连续重连次数，当连续重连这么多次都失败时，不再重连。0和负数则一直重连
     */
    private int retryCount = 0;
    /**
     * 重连的间隔时间，单位毫秒
     */
    private long interval = 5000;


    public ReConnectConfiguration() {
        if (threadPoolExecutor == null) {
            synchronized (ReConnectConfiguration.class) {
                if (threadPoolExecutor == null) {
                    LinkedBlockingQueue<Runnable> tioQueue = new LinkedBlockingQueue<>();
                    String tioThreadName = "io-client-reconnect";
                    DefaultThreadFactory defaultThreadFactory = DefaultThreadFactory.getInstance(tioThreadName, Thread.MAX_PRIORITY);
                    threadPoolExecutor = new LockCapableRunnableThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors(), 60L, tioQueue,
                            defaultThreadFactory, tioThreadName);

                }
            }

        }

    }

    public ReConnectConfiguration(long interval) {
        this();
        this.setInterval(interval);
    }


    public ReConnectConfiguration(long interval, int retryCount) {
        this();
        this.interval = interval;
        this.retryCount = retryCount;
    }

    public static ReConnectConfiguration getReConnectConfiguration(ClientAsynchronousSocketChannelContext clientChannelContext) {
        ClientConfiguration clientConfiguration = (ClientConfiguration) clientChannelContext.clientConfiguration;
        ReConnectConfiguration reConnectConfiguration = clientConfiguration.getReConnectConfiguration();
        return reConnectConfiguration;
    }


    /**
     * @param clientChannelContext
     * @param putIfNeedConnect     如果需要重连，则把该ClientChannelContext放到重连队列中
     * @return
     */
    public static boolean isNeedReConnect(ClientAsynchronousSocketChannelContext clientChannelContext, boolean putIfNeedConnect) {
        if (clientChannelContext == null) {
            return false;
        }
        ReConnectConfiguration reConnectConfiguration = getReConnectConfiguration(clientChannelContext);
        if (reConnectConfiguration == null) {
            return false;
        }

        if (reConnectConfiguration.getInterval() > 0) {
            if (reConnectConfiguration.getRetryCount() <= 0 || reConnectConfiguration.getRetryCount() > clientChannelContext.getReConnectCount().get()) {
                if (putIfNeedConnect) {
                    ClientConfiguration clientConfiguration = (ClientConfiguration) clientChannelContext.clientConfiguration;
                    clientConfiguration.closeds.add(clientChannelContext);
                    clientChannelContext.channelState.timeInReconnQueue = Clock.currentTimeMillis;
                    reConnectConfiguration.getQueue().add(clientChannelContext);
                }

                return true;
            } else {
                log.info("不需要重连{}", clientChannelContext);
                return false;
            }
        }

        return false;
    }

    /**
     * @param clientChannelContext
     * @return true:需要重连;     false:不需要重连
     */
    public static boolean put(ClientAsynchronousSocketChannelContext clientChannelContext) {
        if (clientChannelContext == null) {
            return false;
        }
        return isNeedReConnect(clientChannelContext, true);
    }

}
